﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using Common;
using System.Threading;
using System.Diagnostics;

namespace Network
{
   
    public class ExternalServiceManager
    {
        private CommonDataStorage CDS;
        private volatile bool enable;
        private object lockerEnable = new object();
        private TcpListener listener;
        private ConcurrentBag<string> commonMessageStorage;
        private System.Threading.Timer pollingTimer;

        public bool Enable
        {  
            
            get 
            {
            //    lock (lockerEnable)
            //    {
                    return enable; //
            //    }
            }
        }

        public ExternalServiceManager(CommonDataStorage cds)
        {
            this.CDS = cds;
            commonMessageStorage = new ConcurrentBag<string>();
            
        }

        public void Start()
        {
            enable = true;
            Thread listnerThread = new Thread(ListenerThread);
            listnerThread.IsBackground = true;
            listnerThread.Name = "Listener";
            listnerThread.Start();

            pollingTimer = new Timer(PerformPolling, null, 10000, 20000);//big value for debug

        }

        public void Stop()
        {
            lock (lockerEnable)
            {
                enable = false;
            }
            pollingTimer.Dispose();
            //
        }

        private void ListenerThread()
        {
            try
            {
#warning ip&port should be in config
                IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
                listener = new TcpListener(ipAddress, 5555);
                listener.Start();
                while (this.Enable)
                {
                    Socket clientSocket = listener.AcceptSocket();
                    Thread extServiceReader = new Thread(MaintainExtService);//should I put join there?
                    extServiceReader.IsBackground = true;
                    extServiceReader.Start(clientSocket);
                }
            }
            catch (Exception e)
            {
                Debug.WriteLine(e.Message);
            }
            finally
            {
                if (listener != null)
                    listener.Stop();
            }
        }

        private void PerformPolling(object data)
        {
            // if (CDS.Variables.Count > 0 && commodMessageStorage.Count > 0)
#warning this line takes place only for debug, previous one is correct
            if ( commonMessageStorage.Count > 0)//
            {
                List<String> localStorage = new List<string>();
                while (!commonMessageStorage.IsEmpty)
                {
                    string item;
                    if (commonMessageStorage.TryTake(out item))
                        localStorage.Add(item);
                }

                foreach (string item in localStorage)
                {
                    string[] nameAndValue = ParseCommand(item);
                    var variable = (from var in CDS.Variables
                                    where var.Name == nameAndValue[0]
                                    select var).FirstOrDefault();
                    if (variable != null)
                    {
                        variable.CurrentValue = nameAndValue[1];
                    }
                    else
                    {
                        // maybe it's necessary to send some negative token
                    }
                }
            }
        }


        private void MaintainExtService(object socket)
        {
            Socket socketToReadFrom = (Socket)socket;
            byte[] bufferEmpty = new byte[1];
            socketToReadFrom.Send(bufferEmpty);// to show putted charracters in telnet window

            while (this.Enable)//(enable)
            {
                string recievedValue = string.Empty;
                while(true)
                {
                    byte[] buffer = new byte[512];
                    
                    int recievedBytes = socketToReadFrom.Receive(buffer);
                                        
                    recievedValue += Encoding.ASCII.GetString(buffer, 0, recievedBytes);                    
                    if (recievedValue.IndexOf("\r\n") > -1)
                    {
                        commonMessageStorage.Add(recievedValue);
                        break;
                    }
                }                
            }
            socketToReadFrom.Shutdown(SocketShutdown.Both);
            socketToReadFrom.Close();

        }

        private string[] ParseCommand(string command)
        {
            command = command.Replace("\r\n", "");
            char ch = '=';
            string[] itemsAction = command.Split(new[] { ch }, StringSplitOptions.None);

            return itemsAction;
        }
    }
}
